<?php

namespace app\services;


use app\level\LevelFactory;
use app\payment\PayFactory;
use app\traits\Page;
use BaconQrCode\Encoder\QrCode;
use plugin\admin\app\common\Util;
use plugin\admin\app\model\Application;
use plugin\admin\app\model\Exchange;
use plugin\admin\app\model\ExchangeApply;
use plugin\admin\app\model\ExchangeImage;
use plugin\admin\app\model\Goods;
use plugin\admin\app\model\GoodsSKU;
use plugin\admin\app\model\Like;
use plugin\admin\app\model\Notice;
use plugin\admin\app\model\Order;
use plugin\admin\app\model\OrderGoods;
use plugin\admin\app\model\Reservation;
use plugin\admin\app\model\User;
use plugin\admin\app\model\UserAddress;
use plugin\admin\app\model\UserChat;
use plugin\admin\app\model\UserChatMessage;
use plugin\admin\app\model\UserCollect;
use plugin\admin\app\model\UserFollowing;
use plugin\admin\app\model\UserHistory;
use plugin\admin\app\model\UserIdentify;
use plugin\admin\app\model\UserLevel;
use plugin\admin\app\model\UserLevelGoods;
use plugin\admin\app\model\UserProfile;
use plugin\admin\app\model\UserProperty;
use plugin\admin\app\model\UserPropertyLog;
use plugin\admin\app\model\UserRecommendTeam;
use plugin\admin\app\model\UserTeam;
use plugin\admin\app\model\UserUpline;
use Respect\Validation\Rules\Date;
use SimpleSoftwareIO\QrCode\Generator;
use support\Db;
use support\Log;
use support\Redis;
use Webman\Config;
use Webman\Event\Event;

class UserService
{
    public static function register($data)
    {
        if (!empty($data['mobile']) && User::where('mobile', $data['mobile'])->first()) {
            throw new \Exception('该手机号已被注册');
        }

        if (!empty($data['email']) && User::where('email', $data['email'])->first()) {
            throw new \Exception('该邮箱已被注册');
        }

        $parentId = 0;

        if (!empty($data['invite_code'])) {
            if (! ($parent = User::where('invite_code', $data['invite_code'])->first())) {
                throw new \Exception('不正确的邀请码');
            }

            $parentId = $parent['id'];
        }

        $insertData = [
            'mini_open_id' => $data['openId'] ?? null,
            'mobile' => $data['mobile'] ?? null,
            'email' => $data['email'] ?? null,
            'created_at' => date('Y-m-d H:i:s'),
            'join_time' => date('Y-m-d H:i:s'),
            'invite_code' => NameCardService::generateInviteCode(),
            'temp_parent_id' => $parentId,
            'no' => self::generateUniqueUserNumber()
        ];

        if (!empty($data['password'])) {
            $insertData['password'] = Util::passwordHash($data['password']);
        }

        if (!empty($data['pay_password'])) {
            $insertData['pay_password'] = Util::passwordHash($data['pay_password']);
        }

        $userId = User::insertGetId($insertData);

        UserProfile::insert(['user_id' => $userId, 'nickname' => $data['nickname'] ?? '昵称' . random_int(10000, 99999), 'avatar' => $data['avatar'] ?? '/assets/images/logo.png', 'desc' => '', 'no' => substr(uniqid(), -8)]);
        UserTeam::insert(['user_id' => $userId]);
        UserProperty::insert(['user_id' => $userId]);
        UserUpline::insert(['user_id' => $userId]);

        Event::dispatch('user.register', [$userId, $parentId, $data]);

        return $userId;
    }

    public static function generateUniqueUserNumber()
    {
        do {
            $uniqueNumber = 'GT' . str_pad(random_int(0, 9999999), 7, '0', STR_PAD_LEFT);
        } while (User::where('no', $uniqueNumber)->exists());

        return $uniqueNumber;
    }

    public static function bindParent($userId, $parentId, $data = [])
    {
        print_r(func_get_args());
        if (empty($parentId)) {
            return;
        }

        if ($parentId == $userId) {
            throw new \Exception('不能绑定自己');
        }

        if ($upline = UserUpline::where('user_id', $userId)->value('upline')) {
            throw new \Exception('该用户已绑定上级');
        }

        if (!($parentInfo = User::find($parentId))) {
            throw new \Exception('不存在的上级');
        }

        //设置上级和上级的上级
        User::where('id', $userId)->update([
            'parent_id' => $parentInfo['id'],
            'grant_parent_id' => $parentInfo['parent_id'],
            'grant_parent_id2' => $parentInfo['grant_parent_id'],
            'grant_parent_id3' => $parentInfo['grant_parent_id2'],
            'grant_parent_id4' => $parentInfo['grant_parent_id3'],
        ]);

        //初始化上级线
        $parentIds = UpLineService::get($parentId);
        array_unshift($parentIds, $parentId);
        $parentIds[] = '';
        array_unshift($parentIds, '');
        UserUpline::where('user_id', $userId)->update(['upline' => join(',', $parentIds)]);

        //新增上级直推人数
        UserTeam::where('user_id', $parentInfo['id'])->increment('recommend_count', 1);
        UserTeam::where('user_id', $parentInfo['parent_id'])->increment('level2_count', 1);
        UserTeam::where('user_id', $parentInfo['grant_parent_id'])->increment('level3_count', 1);
        UserTeam::where('user_id', $parentInfo['grant_parent_id2'])->increment('level4_count', 1);
        UserTeam::where('user_id', $parentInfo['grant_parent_id3'])->increment('level5_count', 1);
        UserTeam::where('user_id', $parentInfo['grant_parent_id4'])->increment('level6_count', 1);

        //新增上面一条线所有人的团队人数
        UserTeam::whereIn('user_id', $parentIds)->increment('team_count', 1);
    }

    public static function search($keyword, $page = 1, $length = 10)
    {
        $offset = ($page - 1) * $length;

        $query = UserProfile::select(['user_id', 'nickname', 'avatar', 'fans_count', 'desc', 'no'])->where('nickname', 'like', "%$keyword%")->orWhere('no', $keyword);

        $totalCount = (clone $query)->count();
        $list = $query->offset($offset)->limit($length)->get()->toArray();

        $followings = UserFollowing::where('user_id', get_user_id())->get()->toArray();
        $followings = array_combine(
            array_column($followings, 'follow_user_id'),
            array_values($followings)
        );

        foreach ($list as $key=>$value) {
            $list[$key]['avatar'] = full_url($value['avatar']);
            $list[$key]['is_follow'] = isset($followings[$value['user_id']]);
        }

        return Page::wrap($totalCount, $page, $length, $list);
    }

    public static function generateQrcode($userId, $inviteCode)
    {
        $path = '/qrcode/' . $userId . '.png';
        (new Generator())->size(300)->format('png')->generate(full_url('/?invite_code=' . $inviteCode), public_path($path));

        UserProfile::where('user_id', $userId)->update(['invite_qrcode_url' => $path]);
    }

    public static function generateNickname($mobile)
    {
        return $mobile;
    }

    public static function upgradeToVip($userId)
    {
        User::where('id', $userId)->where('level', '<', 2)->update(['level' => 2]);
    }

    public static function createOrder($payWay, $level = 1, $payWayType = 'h5')
    {
        $user = User::where('id', get_user_id())->first();
        // Generate a unique order number
        $orderNo = OrderService::generateOrderNo();

        $userLevelInfo = UserLevel::where('id', $level)->first();

        if ($user['is_vip'] && $user['level'] > $level) {
            throw new \Exception('不能降级');
        }

        if (!$user['is_vip']) {
            $levelType = 1;
        } else {
            if ($user['level'] == $level) {
                $levelType = 2;
            } else {
                $levelType = 1;
            }
        }

        // Create the order
        $orderData = [
            'order_no' => $orderNo,
            'user_id' => get_user_id(),
            'price' => $userLevelInfo['price'], // Example price for upgrading membership
            'type' => Order::TYPE_UPGRADE_VIP,
            'pay_way' => $payWay,
            'pay_way_type' => $payWayType,
            'status' => Order::STATUS_WAITING_PAY,
            'created_time' => date('Y-m-d H:i:s'),
            'level' => $level,
            'level_type' => $levelType
        ];
        Order::insert($orderData);

        // Prepare the response
        $response = ['order_no' => $orderNo];

        // If payment method is WeChat, generate WeChat payment parameters
        if ($payWay === Order::PAY_TYPE_WECHAT) {
            $paymentParams = PayFactory::create($payWay)->setData([
                'pay_way_type' => $payWayType,
                'order_no' => $orderNo,
                'total_amount' => $orderData['price'],
            ])->pay();

            $response['payment_params'] = $paymentParams;
        } elseif ($payWay === Order::PAY_TYPE_BALANCE) {
            PayFactory::create($payWay)->setData([
                'order_no' => $orderNo,
                'total_amount' => $orderData['price'],
                'source' => UserPropertyLog::PAY_ORDER
            ])->pay();
        }

        if ($payWay == Order::PAY_TYPE_BALANCE) {
            self::paySuccess($orderNo);
        }

        return $response;
    }

    public static function getExchangeRate($from , $to)
    {
        return 7.2211;
    }

    public static function paySuccess($orderNo)
    {
        $order = Order::where('order_no', $orderNo)->first();

        $order->status = Order::STATUS_FINISH;
        $order->pay_time = date('Y-m-d H:i:s');
        $order->save();

        VIPService::toVip($order['user_id'], $order['level']);
    }

    public static function createApplication(array $data)
    {
        // 验证必填字段
        $requiredFields = [
            'companyName', 'contactName', 'phone', 'email', 'address',
            'customerType', 'designId', 'designSource', 'hasAuthorization',
            'sizeLengthMm', 'sizeWidthMm', 'pressingMethod', 'aluminumMethod',
            'filmMethod', 'quantity', 'deliveryAddress', 'expectedDate',
            'logisticsMethod', 'serviceCharge', 'paperCharge', 'totalCharge'
        ];


        // 插入数据
        $insertData = [
            'user_id' => get_user_id(),
            'company_name' => $data['companyName'],
            'contact_name' => $data['contactName'],
            'phone' => $data['phone'],
            'email' => $data['email'],
            'address' => $data['address'],
            'customer_type' => $data['customerType'],
            'design_id' => $data['designId'],
            'design_source' => $data['designSource'],
            'designer_name' => $data['designerName'] ?? null,
            'has_authorization' => $data['hasAuthorization'],
            'product_usage' => $data['productUsage'] ?? null,
            'special_requirements' => $data['specialRequirements'] ?? null,
            'size_length_mm' => $data['sizeLengthMm'],
            'size_width_mm' => $data['sizeWidthMm'],
            'pressing_method' => $data['pressingMethod'],
            'aluminum_method' => $data['aluminumMethod'],
            'film_method' => $data['filmMethod'],
            'paper_size_length' => intval($data['paperSizeLength']) ?? null,
            'paper_size_width' => intval($data['paperSizeWidth']) ?? null,
            'paper_weight' => intval($data['paperWeight']) ?? null,
            'paper_type' => $data['paperType'] ?? null,
            'other_paper_type' => $data['otherPaperType'] ?? null,
            'is_paper_specified' => $data['isPaperSpecified'] ?? 0,
            'specified_paper' => $data['specifiedPaper'] ?? null,
            'quantity' => $data['quantity'],
            'other_requirements' => $data['otherRequirements'] ?? null,
            'delivery_address' => $data['deliveryAddress'],
            'expected_date' => date('Y-m-d', strtotime($data['expectedDate'])),
            'logistics_method' => $data['logisticsMethod'],
            'design_files' => json_encode($data['designFileUrls']) ?? null,
            'modification_files' => json_encode($data['modificationFileUrls']) ?? null,
            'service_charge' => $data['serviceCharge'],
            'paper_charge' => $data['paperCharge'],
            'total_charge' => $data['totalCharge'],
            'need_invoice' => $data['needInvoice'] ?? 0,
            'invoice_title' => $data['invoiceTitle'] ?? null,
            'remark' => $data['remark'] ?? null,
        ];

        return Application::insertGetId($insertData);
    }

    public static function getApplicationList($page, $length)
    {

        $query = Application::where('user_id', get_user_id())
            ->orderByDesc('created_at');

        $list = $query->paginate($length, ['*'], 'page', $page);

        foreach ($list as &$item) {
            $item['created_at'] = date('Y-m-d H:i:s', strtotime($item['created_at']));
            $item['design_files'] = json_decode($item['design_files'], true);
            $item['modification_files'] = json_decode($item['modification_files'], true);
        }

        return $list;
    }


    public static function profile($userId = null)
    {
        if (is_null($userId)) {
            $userId = get_user_id();
        }

        $userProfile = UserProfile::select(['user_id', 'nickname', 'avatar', 'sex', 'birthday', 'real_name'])->where('user_id', $userId)->firstOrFail()->toArray();

        $propertyInfo = UserProperty::select(['balance', 'freeze_balance', 'commission', 'freeze_commission'])->where('user_id', $userProfile['user_id'])->first()->toArray();

        $userProfile['age'] = (new \DateTime())->diff(new \DateTime($userProfile['birthday']))->y;

        $userInfo = User::select(['id', 'is_vip', 'is_creator', 'invite_code', 'expiry_time', 'mobile', 'status', 'no', 'level', 'join_time', 'pay_password', 'password', 'email', 'download_count'])->where('id', $userProfile['user_id'])->first()->toArray();

        $userInfo['format_mobile'] = format_mobile($userInfo['mobile']);
        $userInfo['format_email'] = format_mobile($userInfo['email']);

        $userInfo = $userProfile + $propertyInfo + $userInfo;

        $userInfo['join_time'] = date('Y-m-d', strtotime($userInfo['join_time']));
        $userInfo['expiry_time'] = date('Y-m-d', $userInfo['expiry_time']);

        $userInfo['is_set_pay_password'] = boolval($userInfo['pay_password']);
        $userInfo['has_password'] = boolval($userInfo['password']);
        $userInfo['avatar'] = full_url($userInfo['avatar']);

        unset($userInfo['mobile'], $userInfo['pay_password'], $userInfo['password'], $userInfo['email']);

        $userInfo['add_link'] = build_edit_tools_url('create');

        $userInfo['limit_work_count'] = ConfigService::get('normal_member_work_count');

        $userInfo['factory_info'] = DesignerApplicationService::getDetail($userId);

        $userInfo['level_info'] = UserLevelService::getLevelInfo($userInfo['level']);

        return $userInfo;
    }

    public static function getProfileRate($userInfo)
    {
        $rate = 0;

        foreach (['birthday', 'sex', 'school', 'musical_instrument'] as $field) {
            if (!empty($userInfo[$field])) {
                $rate += 20;
            }
        }

        if (AddressService::hasOne($userInfo['user_id'])) {
            $rate += 20;
        }

        return $rate;
    }

    public static function myParent()
    {
        $user = User::select(['parent_id'])->where('id', get_user_id())->first();

        if ($user['parent_id'] == 0) {
            return [
                'exists' => false,
                'nickname' => '',
                'avatar' => '',
                'no' => '',
                'wechat_no' => '',
                'qq' => '',
                'show_full_mobile' => '',
                'mobile' => ''
            ];
        }

        $parentTeamInfo = UserTeam::select(['recommend_count'])->where('user_id', $user['parent_id'])->first();
        $parentInfo = User::select(['no', 'mobile'])->where('id', $user['parent_id'])->first();
        $parentProfileInfo = UserProfile::select(['nickname', 'avatar', 'wechat_no', 'qq', 'show_full_mobile'])->first();

        return [
            'exists' => true,
            'recommend_count' => $parentTeamInfo['recommend_count'],
            'nickname' => $parentProfileInfo['nickname'],
            'avatar' => $parentProfileInfo['avatar'],
            'no' => $parentInfo['no'],
            'wechat_no' => $parentProfileInfo['wechat_no'],
            'qq' => $parentProfileInfo['qq'],
            'show_full_mobile' => $parentProfileInfo['show_full_mobile'],
            'mobile' => $parentProfileInfo['show_full_mobile'] ? $parentInfo['mobile'] : ''
        ];

    }

    public static function teamInfo()
    {
        $teamInfo = UserTeam::select(['recommend_count', 'identify_recommend_count'])->where('user_id', get_user_id())->first();

        $rate = 10;
        $currentPrice = 16;
        $speedUp = bcmul($teamInfo['identify_recommend_count'], $currentPrice, 2);
        $speedUp = bcmul($speedUp, $rate/100, 2);

        $teamList = self::teamList(1, 10, true, false);

        return [
            'team_info' => $teamInfo,
            'team_list' => $teamList,
            'speed_up' => $speedUp,
            'formula' => $teamInfo['identify_recommend_count'] . ' x ' . $rate . '% x ' . $currentPrice,
            'each_rate' => $rate
        ];
    }

    public static function teamList($page, $length = 10, $isIdentify = null, $pagination = true)
    {
        $offset = ($page - 1) * $length;
        $query = User::select(['id', 'created_at'])->where('parent_id', get_user_id());

        if ($isIdentify) {
            $query = $query->where('is_identify', $isIdentify);
        }

        $totalCount = (clone $query)->count();
        $list = $query->offset($offset)->limit($length)->get()->toArray();

        $userIds = array_column($list, 'id');
        $userProfiles = UserProfile::select(['user_id', 'nickname', 'avatar'])->whereIn('user_id', $userIds)->get()->toArray();
        $userProfiles = array_combine(
            array_column($userProfiles, 'user_id'),
            array_values($userProfiles)
        );

        foreach ($list as $key=>$item) {
            $list[$key]['nickname'] = $userProfiles[$item['id']]['nickname'];
            $list[$key]['avatar'] = $userProfiles[$item['id']]['avatar'];
        }

        if ($pagination) {
            return Page::wrap($totalCount, $page, $length, $list);
        }

        return $list;
    }

    public static function identifyInfo()
    {
        $userInfo = User::select(['is_identify'])->where('id', get_user_id())->first();

        $identifyInfo = UserIdentify::select(['name', 'idcard'])->where('user_id', get_user_id())->first();

        return [
            'is_identify' => $userInfo['is_identify'],
            'name' => isset($identifyInfo['name']) ? hideTrueName($identifyInfo['name']) : '',
            'idcard' => isset($identifyInfo['idcard']) ? hideIdCardNo($identifyInfo['idcard']) : ''
        ];
    }

    public static function isBindAliPay()
    {
        $userInfo = User::select(['alipay_open_id'])->where('id', get_user_id())->first();

        return ['is_bind' => !is_null($userInfo['alipay_open_id'])];
    }

    public static function basicProfile($id)
    {
        $user = UserProfile::select(['user_id', 'nickname', 'avatar', 'fans_count', 'follow_count'])->where('user_id', $id)->first();

        if (!$user) {
            throw new \Exception('不存在的用户');
        }

        return $user;
    }

    public static function saveProfile($data)
    {
        $updateData = [];

        $allowedFields = ['nickname', 'avatar', 'birthday', 'real_name', 'sex', 'school', 'province', 'city', 'district', 'musical_instrument'];
        foreach ($data as $key=>$item) {
            if (in_array($key, $allowedFields)) {
                $updateData[$key] = $item;
            }
        }

        if ($updateData) {
            UserProfile::where('user_id', get_user_id())->update($updateData);
        }
    }

    public static function ifFinishProfileSendBalance()
    {
        if (UserPropertyLog::where('user_id', get_user_id())->where('source', UserPropertyLog::FINISH_PROFILE)->count() == 0) {
            $profile = self::profile();

            if ($profile['finish_rate'] >= 100) {
                PropertyService::add(get_user_id(), PayFactory::BALANCE, 100, UserPropertyLog::FINISH_PROFILE);
            }
        }
    }

    public static function savePayPassword($data)
    {
        User::where('id', get_user_id())->update([
            'pay_password' => Util::passwordHash($data['password']),
        ]);
    }

    public static function friends($page, $length, $level = 0, $name = '')
    {
        $offset = ($page - 1) * $length;
        $query = User::select(['id', 'nickname', 'avatar', 'level', 'mobile', 'join_time'])->where('parent_id', get_user_id());

        if ($level) {
            $query = $query->where('level', $level);
        }

        if ($name) {
            $query = $query->where('nickname', 'like', "%{$name}%");
        }

        $count = (clone $query)->count();
        $list = $query->offset($offset)->limit($length)->orderByDesc('join_time')->get()->toArray();

        $userLevels = UserLevel::list();
        $userLevels = array_combine(
            array_column($userLevels, 'value'),
            array_column($userLevels, 'name')
        );

        foreach ($list as $key=>$item) {
            $list[$key]['level_text'] = $userLevels[$item['level']];
            $list[$key]['mobile'] = format_mobile($item['mobile']);
        }

        return Page::wrap($count, $page, $length, $list);
    }

    public static function levels()
    {
        return UserLevel::list();
    }

    public static function addTeamConsume($userId, $price)
    {
        $uplineArr = UpLineService::get($userId);

        if ($uplineArr && $price > 0) {
            UserTeam::whereIn('user_id', $uplineArr)->increment('team_consume', $price);
        }
    }

    public static function isVip($userId)
    {
        $userInfo = self::profile($userId);
        return $userInfo['is_vip'] == 1;
    }

    public static function getRebateRate($userInfo)
    {
        $level = UserLevel::where('id', $userInfo['level'] ?? 0)->first();

        return $level['rebate'] ?? 0;
    }

    public static function getOpenId($order)
    {
        $openId = '';

        $user = User::where('id', $order['user_id'])->first();

        if ($order['pay_way'] == 'wechat') {
            switch ($order['pay_way_type']) {
                case 'mini':
                    return $user['mini_open_id'] ?? '';
                case 'mp':
                    return $user['mp_open_id'] ?? '';
            }
        }

        return $openId;
    }

    public static function changePassword($oldPassword = '', $newPassword = '')
    {
        $userId = get_user_id();
        $user = User::select(['password'])->where('id', $userId)->first();

        if (!$user) {
            throw new \Exception('用户不存在');
        }

        // 如果用户未设置过密码
        if (empty($user['password'])) {
            if (empty($newPassword)) {
                throw new \Exception('新密码不能为空');
            }

            // 设置新密码
            User::where('id', $userId)->update([
                'password' => Util::passwordHash($newPassword),
            ]);

            return ok_rsp('密码设置成功');
        }

        // 如果用户已设置过密码，校验旧密码
        if (!Util::passwordVerify($oldPassword, $user['password'])) {
            throw new \Exception('旧密码不正确');
        }

        if (empty($newPassword)) {
            throw new \Exception('新密码不能为空');
        }

        // 设置新密码
        User::where('id', $userId)->update([
            'password' => Util::passwordHash($newPassword),
        ]);

        return ok_rsp('密码修改成功');
    }
}